import io from 'socket.io-client';

export class SocketIo {
    constructor (settings, options) {
        this.socketClient = null;
        this.settings = {
            url: '',
            connect: function () { },
            disconnect: function () { },
            ping: function () { },
            pong: function () { },
            connect_error: function () { },
            error: function () {
                if (this.socketClient) {
                    this.socketClient.disconnect();
                }
            },
            ...settings
        };
        this.init(options);
    }

    /**
     * socketio初始化
    */
    init (options) {
        const _this = this;
        console.log('[socketio]初始化socket连接，服务端url[' + _this.settings.url + ']');
        const socketUrl = `http://${_this.settings.url}`;
        this.socketClient = io(socketUrl, {
            reconnectionAttempts: 20,
            reconnection: true,
            ...options
        });
        this.socketClient.on('connect', function () {
            console.log('[socketio] The client has connected to the server!, socket.ids:' + _this.socketClient.ids);
            _this.settings.connect.call && _this.settings.connect.call(_this);
        });
        this.socketClient.on('disconnect', function () {
            console.log('[socketio] The client has disconnected!');
            _this.settings.disconnect.call && _this.settings.disconnect.call(_this);
        });
        // 这里实际上处理的是server端推送的事件名为'ping'的事件，而不是socketio协议内部实现的ping机制，下面的pong也是一样
        this.socketClient.on('ping', function () {
            console.log('[socketio] a ping packet is written out to the server!');
            _this.settings.ping.call && _this.settings.ping.call(_this);
        });
        this.socketClient.on('pong', function () {
            console.log('[socketio] a pong is received from the server!');
            _this.settings.pong.call && _this.settings.pong.call(_this);
        });
        this.socketClient.on('connect_error', function () {
            console.log('[socketio] a connection error!');
            _this.settings.connect_error.call && _this.settings.connect_error.call(_this);
        });
        this.socketClient.on('error', function () {
            console.log('[socketio] an error occurs!');
            _this.settings.error.call && _this.settings.error.call(_this);
        });
        // 内部心跳包监听
        this.socketClient.io.engine.on("packet", (packet) => {
            if (packet.type === "ping") {
                console.log('[socketio] 收到服务器 ping');
                _this.settings.pingReceived.call && _this.settings.pingReceived.call(_this);
            }
        });
    }

    /**
     * 关闭连接
     */
    close () {
        this.socketClient.close();
    }

    /**
     * 发送数据
     * eventName：事件名称
     * data ：发送的数据
     */
    emit (eventName, data) {
        const _this = this;
        if (this.socketClient) {
            this.socketClient.emit(eventName, data);
            console.log('[socketio]发送数据，事件[' + eventName + '];数据：' + JSON.stringify(data));
        } else {
            console.log('[socketio]socketio未连接');
            this.init({
                connect: function () {
                    _this.socketClient.emit(eventName, data);
                }
            });
        }
    }

    /**
     * 绑定指定事件
     * eventName：事件名称
     * callback：事件返回数据函数
     */
    on (eventName, callback) {
        const _this = this;
        if (this.socketClient) {
            this.socketClient.on(eventName, function (data) {
                if (callback) {
                    console.log('socket id：' + _this.socketClient.ids);
                    callback.call && callback.call(_this, data);
                }
            });
            console.log('[socketio]绑定[' + eventName + ']事件');
        } else {
            console.log('[socketio]socketio未连接');
            this.init({
                connect: function () {
                    _this.socketClient.on(eventName, callback);
                }
            });
        }
    }

    /**
   * 解绑指定事件
   * eventName: 事件名
   * callback: 事件回调
   */
    off (eventName) {
        const _this = this;
        if (this.socketClient) {
            this.socketClient.off(eventName, function () {
                console.log('socket id：' + _this.socketClient.ids);
                console.log('[socketio]解绑[' + eventName + ']事件');
            });
        } else {
            console.log('[socketio]socketio未连接');
        }
    }
}
